package org.example.easybuy.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.conn.routing.RouteInfo;
import org.example.easybuy.entity.*;
import org.example.easybuy.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.Address;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class CarDetailServiceImpl implements CarService {


    @Autowired
    private ProductService productService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderService orderService;
    ObjectMapper objectMapper=new ObjectMapper();
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Map<String,Object> addIntoCar(String loginName, CarDetail carDetail) throws JsonProcessingException {
        Map<String,Object> resultMap=new HashMap<>();
        Product product=productService.selectById(carDetail.getId().toString());
        if(product.getStock()-carDetail.getNum()>0)
        {
            Map<Integer,CarDetail> map;
            double totalPrice=0;
            int total=0;
            if(stringRedisTemplate.hasKey(loginName+"_car"))
            {
                //redis中的旧map
                String oldCarStr= stringRedisTemplate.opsForValue().get(loginName+"_car");
                Car oldCar=objectMapper.readValue(oldCarStr,Car.class);
                Map<Integer,CarDetail> params=new HashMap<>();
                map=oldCar.getCarDetailMap();
                boolean flag=false;
                for(Integer key :map.keySet())
                {

                    CarDetail value=map.get(key);
                    if(carDetail.getId().toString().equals(value.getId().toString()))
                    {
                        //相同的商品
                        flag=true;
                        CarDetail detail=map.get(value.getId());
                        detail.setNum(detail.getNum()+carDetail.getNum());
                        detail.setNumPrice(detail.getPrice()*detail.getNum());
                        params.put(value.getId(),detail);
                    }else{
                        //放入新的map
                        params.put(key,value);
                    }
                    total+=value.getNum();
                    totalPrice+=value.getNumPrice();
                }
                if(!flag)
                {
                    params.put(carDetail.getId(),carDetail);
                    total+=carDetail.getNum();
                    totalPrice+= carDetail.getNumPrice();
                }
                Car car=new Car();
                car.setTotalNum(total);
                car.setLoginName(loginName);
                car.setTotalPrice(totalPrice);
                car.setCarDetailMap(params);
                stringRedisTemplate.opsForValue().set(loginName+"_car",objectMapper.writeValueAsString(car));
            }else{
                total=carDetail.getNum();
                totalPrice= carDetail.getNumPrice();
                map=new HashMap<>();
                map.put(carDetail.getId(),carDetail);
                Car car=new Car();
                car.setTotalNum(total);
                car.setLoginName(loginName);
                car.setTotalPrice(totalPrice);
                car.setCarDetailMap(map);
                stringRedisTemplate.opsForValue().set(loginName+"_car", objectMapper.writeValueAsString(car));
            }
            String newCarStr= stringRedisTemplate.opsForValue().get(loginName+"_car");
            Car newCar=objectMapper.readValue(newCarStr,Car.class);
            resultMap.put("car",newCar);
            resultMap.put("isAdd","yes");
            return resultMap;
        }else{
            resultMap.put("isAdd","no");
            return resultMap;
        }
    }

    @Override
    public boolean deleteDetail(int id,String loginName) throws JsonProcessingException {
        if(stringRedisTemplate.hasKey(loginName+"_car"))
        {
            String carJson=stringRedisTemplate.opsForValue().get(loginName+"_car");
            Car car=objectMapper.readValue(carJson,Car.class);
            Map<Integer,CarDetail> detailMap=car.getCarDetailMap();
            if(detailMap.containsKey(id))
            {
                try{
                    car.setTotalNum(car.getTotalNum()-detailMap.get(id).getNum());
                    car.setTotalPrice(car.getTotalPrice()-detailMap.get(id).getNumPrice());
                    detailMap.remove(id);
                    car.setCarDetailMap(detailMap);
                    stringRedisTemplate.opsForValue().set(loginName+"_car",objectMapper.writeValueAsString(car));
                }catch(RuntimeException e)
                {
                    return false;
                }
                return true;
            }else{
                return false;
            }
        }
        return false;
    }

    @Override
    public boolean updateCarFromRedis(List<CarDetail> list,String loginName) throws JsonProcessingException {
        String carJson=stringRedisTemplate.opsForValue().get(loginName+"_car");
        Car car=objectMapper.readValue(carJson,Car.class);
        int num=0;
        double totalPrice=0;
        Map<Integer,CarDetail> detailMap=car.getCarDetailMap();
        try{
            for(CarDetail d:list)
            {
                if(detailMap.containsKey(d.getId()))
                {
                    detailMap.put(d.getId(),d);
                }
            }
            for(Integer key:detailMap.keySet())
            {
                CarDetail c=detailMap.get(key);
                num+=c.getNum();
                totalPrice+=c.getNumPrice();
            }
            car.setTotalNum(num);
            car.setTotalPrice(totalPrice);
            car.setCarDetailMap(detailMap);
            stringRedisTemplate.opsForValue().set(loginName+"_car",objectMapper.writeValueAsString(car));
        }catch(RuntimeException e)
        {
            return false;
        }
        return true;
    }

    @Transactional
    @Override
    public Order generateOrder(Map<String, Object> map) throws JsonProcessingException {
        List<CarDetail> list=new ArrayList<>();
        //明细列表
        list=objectMapper.readValue(map.get("list").toString(),objectMapper.getTypeFactory().constructCollectionType(List.class,CarDetail.class));
        //获取地址
        UserAddress address=objectMapper.readValue(map.get("address").toString(),UserAddress.class);
        //生成订单号
        String orderId= "order_"+UUID.randomUUID().toString();
        String loginName=map.get("loginName").toString();
        //根据登录名查询用户
        User user=userService.getUserByLoginName(loginName);
        //设置订单信息
        Order order=new Order();
        order.setUserId(user.getId());
        order.setSerialNumber(orderId);
        order.setCreateTime(new Date());
        order.setCost(Integer.parseInt(map.get("totalPrice").toString()));
        order.setIsDel(0);
        order.setLoginName(loginName);
        order.setUserAddress(address.getAddress());
        order.setIsPay(0);
        try{
            //添加订单
            if(orderService.addOrder(order))
            {
                int id=order.getId();
                //添加明细
                for(CarDetail d:list)
                {
                    //设置明细
                    OrderDetail detail=new OrderDetail();
                    detail.setOrderId(id);
                    detail.setProductId(d.getId());
                    detail.setQuantity(d.getNum());
                    detail.setCost(d.getNumPrice());
                    orderDetailService.addDetail(detail);
                    //更改库存
                    Product product = productService.selectById(d.getId().toString());
                    //减少库存
                    product.setStock(product.getStock()-d.getNum());
                    //增加预出库库存
                    product.setReadyStock(product.getReadyStock()+d.getNum());
                    productService.updateStock(product);
                }
            }
        }catch(RuntimeException e)
        {
            throw new RuntimeException();
        }
        //从redis中删除
        try{
            String carJson=stringRedisTemplate.opsForValue().get(loginName+"_car");
            Car car=objectMapper.readValue(carJson,Car.class);
            Map<Integer,CarDetail> detailMap=car.getCarDetailMap();
            for(CarDetail d:list)
            {
                detailMap.remove(d.getId());
            }
            int num=0;
            double totalPrice=0;
            //重新计算总价和数量
            for(Integer key:detailMap.keySet())
            {
                CarDetail c=detailMap.get(key);
                num+=c.getNum();
                totalPrice+=c.getNumPrice();
            }
            car.setTotalNum(num);
            car.setTotalPrice(totalPrice);
            car.setCarDetailMap(detailMap);
            stringRedisTemplate.opsForValue().set(loginName+"_car",objectMapper.writeValueAsString(car));
        }catch(RuntimeException e)
        {
            throw new RuntimeException();
        }
        //将订单存入redis3分钟
        stringRedisTemplate.opsForValue().set(orderId,"订单",3, TimeUnit.MINUTES);
        return order;
    }

    @Transactional
    @Override
    public void doChangeOrder(String orderId) {
        //查出订单
        Order order=orderService.selectBySerialNumber(orderId);
        //再查出订单下的明细
        List<OrderDetail> list=orderDetailService.selectDetailByIds(order.getId().toString());
        try{
            for(OrderDetail detail:list)
            {
                //根据商品Id查出明细中的商品
                Product product=productService.selectById(detail.getProductId().toString());
                //更改商品的预出库
                product.setReadyStock(product.getReadyStock()-detail.getQuantity());
                //更改商品的库存
                product.setStock(product.getStock()+detail.getQuantity());
                //更改商品的库存
                productService.updateStock(product);
            }
            //更改订单的状态
            orderService.updateOrderStatusById(order.getId());
        }catch(RuntimeException e)
        {
            throw new RuntimeException();
        }
    }
}
